package com.sky.aspect;

import com.sky.anno.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Slf4j
@Aspect     //申明这是一个切面类
@Component  //交给容器管理
public class AutoFillAspect {

    @Before("@annotation(com.sky.anno.AutoFill)")
    public void doFill(JoinPoint joinPoint) {//JoinPoint 连接点对象，包含了目标方法的所有相关信息
        log.info("进行公共字段自动填充");
        //通过joinPoint连接点对象，获得方法签名（需要强转）
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //通过方法签名，获得方法对象
        Method method = signature.getMethod();
        //通过方法对象，获得方法上指定的注解对象
        AutoFill annotation = method.getAnnotation(AutoFill.class);
        //通过注解对象，获得注解中的value值
        OperationType value = annotation.value();

        //提前准备：
        //获取目标方法的 参数对象数组
        Object[] objects = joinPoint.getArgs();
        //如果方法中没有参数，参数对象数组 的长度为0则return
        if (objects.length <= 0) return;
        //获取数组中第1个，也就是实体对象，使用Object类型接收，提高复用性
        Object entity = objects[0];
        //如果第一个对象为空，则return
        if (entity == null) return;

        try {
            if (value == OperationType.INSERT){
                //反射：通过实体对象，获得字节码对象entity.getClass()
                //通过字节码对象，找到里面的方法(根据搜索条件：1、方法名字 2、方法行参.class找到这个方法)
                Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                //拿到里面的方法后，使用这个方法
                setCreateTime.invoke(entity, LocalDateTime.now());
                //下面的创建人、更新日期和更新人同理
                entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class).invoke(entity, BaseContext.getCurrentId());
            }
            entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class).invoke(entity, LocalDateTime.now());
            entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class).invoke(entity, BaseContext.getCurrentId());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
